//
// math64.cpp
// libprotea
// Tools Library for the Protea Project / 64-bit arithmatic for Fields
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Please send correspondence to:
// 
// theproteaproject@gmail.com
//

#include "../defines.h"
#include "fields.h"
#include "math64.h"

//
// Returns 10^-X
//
double PowerOfTen( int x ) {
	double value = 1.0;

	if (x>0)
		do value /= 10; while (--x);
	else if (x)
		do value *= 10; while (++x);

	return value;
};



/*

void matchscale( struct64& result, int scale ) {
	int dif = result.scale - scale;
	if (dif < 0) {
		// Padding value with zeros
		result.value *= PowerOfTen( dif );
	} else if (dif > 0) {
		// Truncation of value, need to worry about rounding problems


		// First, grab rounding digit:
		dif--;
		result.value *= PowerOfTen( dif );
		int tens = result.value % 10;

		// Next, get our real result
		result.value /= 10;

		// Now, determine if we should modify result...
		switch( rounding_mode ) {
			case ROUND_TRUNCATE:
				// Do nothing, we should already truncate normally
				break;

			case ROUND_CEIL:
				break;

			case ROUND_FLOOR:
				break;

			case ROUND_NORMAL:
				if (tens >= 5)
					result.value += 1;

				if (tens <= -5)
					result.value -= 1;
				break;
		};
	};

	result.scale = scale;
};






int int64_addsub( struct64 a, struct64 b, struct64& result, bool adding = true ) {
	struct64 a_temp, b_temp;

	int precision[3];
	int scale[3];
	int savescale;

	precision[0] = a.precision - a.scale;
	precision[1] = b.precision - b.scale;
	scale[0] = a.scale;
	scale[1] = b.scale;

	precision[2] = MAX( precision[0], precision[1] );
	scale[2] = MAX( scale[0], scale[1] );

	// Check for inexact result. If we exceed our digits of precision (minus one for carry)
	// then we can not obtain an exact answer.
	if (precision[2] + scale[2] > 17)
		return INEXACT_RESULT;

	// Pad or truncate to match scale of resulting temp
	a_temp = a;
	b_temp = b;
	matchscale( a_temp, scale[2] );
	matchscale( b_temp, scale[2] );

	// Do the actual mathematics
	if (adding)
		result.value = a_temp.value + b_temp.value;
	else
		result.value = a_temp.value + b_temp.value;

	savescale = result.scale;
	result.scale = scale[2];

	// Check for overflow here...

	// Round final result if necessary
	matchscale( result, savescale );

	return 0;
};
*/
